<?php
/**
 * Description: 获取知识点
 * User: devforma
 * Date: 15/4/10
 * Time: 16:28
 */


require __DIR__ . '/includes/utils.php';

class GetNoteHierarchy implements iController {

    private $userId, $notes;

    /**
     * api请求处理主函数
     * @param array $queryArgs 就是$_REQUEST变量
     * @return array api返回结果，必须含response_code
     */
    public function output($queryArgs) {
        global $uddb;
        
        if (validateUser($queryArgs) !== 1)
            return genOutput(1000);

        $this->userId = $queryArgs['user_id'];

        $allowedType = array('error', 'collect', 'all');
        if (empty($queryArgs['type']) || !in_array($queryArgs['type'], $allowedType))
            return genOutput(1000);

        //获取该用户能看到的知识点
        $userData = getUserData($this->userId);
        if (empty($userData) || empty($userData->note_info))
            return genOutput(1000);

        $shouldShowNewHierarchy = shouldShowNewNoteHierarchy($queryArgs['terminal_type'], $queryArgs['app_version']);

        $availableNotes = array_keys(normalizeUserNoteInfo($userData->note_info));

        $hierarchy = array();
        $tableName = $uddb ->table($uddb ->qbUserTests) -> sublist($this -> userId);
        if ($queryArgs['type'] == 'all') {
            $hierarchy = $this->getNewFilteredHierarchy($availableNotes, true, !$shouldShowNewHierarchy);

        } elseif ($queryArgs['type'] == 'error') {
            //获取错题的知识点
            $sql = "SELECT DISTINCT(`note_id`) FROM `{$tableName}` WHERE `user_id`=:user_id
            AND `test_time` IS NOT NULL AND `is_right`=0";

            $notes = $uddb->getCol($sql, array(':user_id' => $this->userId));
            $notes = array_intersect((array)$notes, $availableNotes);

            $hierarchy = $this->getNewFilteredHierarchy($notes, false, !$shouldShowNewHierarchy);

        } elseif ($queryArgs['type'] == 'collect') {
            //获取收藏题目的知识点
            $sql = "SELECT DISTINCT(`note_id`) FROM `{$tableName}` WHERE `user_id`=:user_id
            AND `collect_time` IS NOT NULL AND `is_collected`=1";
            $notes = $uddb->getCol($sql, array(':user_id' => $this->userId));
            $notes = array_intersect($notes, $availableNotes);

            $hierarchy = $this->getNewFilteredHierarchy($notes, false, !$shouldShowNewHierarchy);
        }
        return genOutput(1, array('hierarchy' => $hierarchy));
    }


    /**
     * 新版知识点层级结构
     *
     * @param array $availableNotes 知识点范围
     * @param bool $showCount 是否计算题数
     * @param bool $limitLevel 是否限制层数
     * @return array
     */
    private function getNewFilteredHierarchy($availableNotes, $showCount = false, $limitLevel = false) {
        $this->notes = getNewNoteHierarchy();

        if (empty($this->notes))
            return array();

        if ($showCount) {
            $counts = $this->getQuestionDoneCount($this->userId); //用户做过的各知识点题目的数量
            $allCounts = $this->getQuestionTotalCount(); //总的各个知识点的题目数量
        } else {
            $counts = $allCounts = array();
        }

        /**--------------------------------------------------------
         * 构造树形结构
         */
        $tree = array();
        $leafNotes = array();
        foreach ($this->notes as $noteId => $note) {
            $this->notes[$noteId]['total'] = 0;
            $this->notes[$noteId]['done'] = 0;

            if ($note['note_type'] == 1) {
                if (!in_array($noteId, $availableNotes) || $noteId == 959 || $noteId == 1512)
                    continue;

                $this->notes[$noteId]['total'] = isset($allCounts[$noteId]) ? $allCounts[$noteId] : 0;
                $this->notes[$noteId]['done'] = isset($counts[$noteId]) && isset($allCounts[$noteId]) ? min($counts[$noteId], $allCounts[$noteId]) : 0;

                //叶子知识点数组
                $leafNotes[] = $this->notes[$noteId];
            }
        }

        //由叶子知识点构造知识点树,根节点直接进行覆盖处理,因为后面得出的根节点包含了前面处理时的结果
        foreach ($leafNotes as $leafNote) {
            $root = $this->findRoot($leafNote);
            $tree[$root['id']] = $root;
        }
        $tree = array_values($tree);

        /**--------------------------------------------------------------
         * 更新各知识点答题数
         */
        foreach ($tree as &$note) {
            $this->updateNoteQuestionCount($note);
        }

        /**--------------------------------------------------------------
         * 老版App构造三层结构
         */
        if ($limitLevel) {
            $newTree = array();
            foreach ($tree as $catIndex => $category) {
                $newTree[$catIndex] = array(
                    'category_id' => $category['id'],
                    'total' => $category['total'],
                    'done' => $category['done'],
                    'name' => $category['name'],
                    'note_group' => array()
                );

                if (!empty($category['childs'])) {
                    foreach ($category['childs'] as $groupIndex => $group) {
                        $newTree[$catIndex]['note_group'][$groupIndex] = array(
                            'group_id' => $group['id'],
                            'total' => $group['total'],
                            'done' => $group['done'],
                            'name' => $group['name'],
                            'notes' => array()
                        );

                        if (!empty($group['childs'])) {
                            foreach ($group['childs'] as $noteIndex => $leafNote) {
                                $newTree[$catIndex]['note_group'][$groupIndex]['notes'][$noteIndex] = array(
                                    'note_id' => $leafNote['id'],
                                    'total' => $leafNote['total'],
                                    'done' => $leafNote['done'],
                                    'name' => $leafNote['name']
                                );
                            }
                        }
                    }
                }
            }

            $tree = $newTree;
        }

        return $tree;
    }


    /**
     * 获取各个知识点下的题目数
     *
     * @return array
     */
    private function getQuestionTotalCount() {
        global $cmsdb;

        $cacheKey = 'function:getQuestionTotalCount';
        if (($counts = cacheGet($cacheKey)) == null) {
            $sql = "SELECT r.note_id, count(r.id) AS count FROM {$cmsdb->questionNoteR} AS r " .
                "JOIN {$cmsdb->oZtkQuestions} AS q ON(r.question_id=q.id) " .
                "WHERE r.note_id!=0 AND q.is_handpick=1 AND q.type=1 GROUP BY r.note_id";
            $results = $cmsdb->getResults($sql);

            $counts = array();
            foreach ($results as $row) {
                $counts[$row->note_id] = intval($row->count);
            }

            cacheAdd($cacheKey, $counts, 12*60*60);
        }

        return $counts;
    }

    /**
     * 获取各个知识点下的做题数
     *
     * @param $userId
     * @return array|bool
     */
    private function getQuestionDoneCount($userId) {
        global $cmsdb, $uddb;

        $qIds = $uddb->table($uddb->qbUserTests)
            ->where('user_id', $userId)
            ->where('user_answer', '!=', '')
            ->lists('question_id');
        if (!$qIds) return false;

        $notes = array();
        $results = $cmsdb->table($cmsdb->questionNoteR)
            ->select('note_id','COUNT(question_id) AS num')
            ->where('note_id', '>', 0)
            ->whereIn('question_id', array_unique($qIds))
            ->groupBy('note_id')
            ->get();
        if ($results) {
            foreach ($results as $row) {
                $notes[$row->note_id] = intval($row->num);
            }
        }

        return $notes;
    }

    /**
     * 查找指定知识点的父节点,并更新父子关系
     *
     * @param array $leafNote 子节点
     * @return array
     */
    private function findRoot(&$leafNote) {
        if (isset($this->notes[$leafNote['parent_id']])) {
            //如果该知识点的父知识点childs已经添加过该知识点了,则进行childs的合并
            if (isset($this->notes[$leafNote['parent_id']]['childs'][$leafNote['id']])) {
                foreach ($leafNote['childs'] as $key => $c) {
                    $this->notes[$leafNote['parent_id']]['childs'][$leafNote['id']]['childs'][$key] = $c;
                }
            } else {
                $this->notes[$leafNote['parent_id']]['childs'][$leafNote['id']] = $leafNote;
            }

            return $this->findRoot($this->notes[$leafNote['parent_id']]);
        }

        return $leafNote;
    }


    /**
     * 更新知识点属性结构的题目信息
     *
     * @param array $note
     * @return mixed
     */
    private function updateNoteQuestionCount(&$note) {
        if (empty($note['childs'])) {
            return array('total' => $note['total'], 'done' => $note['done']);
        } else {
            foreach ($note['childs'] as &$child) {
                $countInfo = $this->updateNoteQuestionCount($child);
                $note['total'] += $countInfo['total'];
                $note['done'] += $countInfo['done'];
            }

            //去除知识点id索引
            $note['childs'] = array_values($note['childs']);

            return array('total' => $note['total'], 'done' => $note['done']);
        }
    }

}
